//--------------------------------------------------------------------------
// 
//  Copyright (c) Chili Software.  All rights reserved. 
// 
//  File: PopulateHelperExtendedMetaInfo.cs
//
//  Description: A mapped member when implementing IPopulateHelperExtended.
// 
//--------------------------------------------------------------------------

using System;
using System.Reflection;

namespace Chili.Opf3.Mapping
{
	/// <summary>
	/// Class represents a meta element that is used to create the mapping between the persistent object and
	/// the field in the table.
	/// </summary>
	/// <remarks>
	/// This class represents a meta element that is used to create the mapping between a field
	/// of the persistent object and a field in the storage table. This class uses the <see cref="IPopulateHelperExtended">IPopulateHelperExtended</see>
	/// interface to set and get the values in/from the persistent's members.
	/// </remarks>
	internal sealed class PopulateHelperExtendedMetaInfo : MetaInfo
	{
		private readonly string NAME;
		private IMemberInfo _fallback;

		/// <summary>
		/// Creates a new instance of the <see cref="PopulateHelperMetaInfo">PopulateHelperMetaInfo Class</see>.
		/// </summary>
		/// <param name="memberInfo">The MemberInfo object that represents the member in the persistent object's type.</param>
		/// <param name="type">Specifies the type of the member.</param>
		/// <param name="attribute">The <see cref="FieldAttribute">FieldAttribute</see> that contains the mapping information.</param>
		/// <param name="fallback">The fallback member if the populate helper is not requested for the given member.</param>
		public PopulateHelperExtendedMetaInfo(MemberInfo memberInfo, Type type, FieldAttribute attribute, IMemberInfo fallback)
			: base(type, memberInfo, attribute)
		{
			_fallback = fallback;
			NAME = memberInfo.Name;
		}

		/// <summary>
		/// Returns the name of the element of the persistent object type that is mapped to the field in the storage.
		/// </summary>
		public override string Name
		{
			get { return NAME; }
		}

		/// <summary>
		/// Returns the value of the element of the persistent object type that is mapped to a field in the storage.
		/// </summary>
		/// <param name="obj">The persistent object that's value is returned.</param>
		/// <returns>Value of the persistent object types's element that is mapped to a field in the storage.</returns>
		public override object GetValue(object obj)
		{
			IPopulateHelperExtended iphe = (IPopulateHelperExtended)obj;
			// Fallback to the other solution, if not supported.
			if (!iphe.PropertyIsHandled(this.NAME))
				return _fallback.GetValue(obj);

			object val = iphe[NAME];

			if (IsUserDefinedType && val != null)
				val = ((IUserDefinedType)val).ToSimpleDataType();

			return val;
		}

		/// <summary>
		/// Sets new value for the element of the persistent object type that is mapped to the storage.
		/// </summary>
		/// <param name="obj">The persistent object that's value is updated.</param>
		/// <param name="value">The new value.</param>
		public override void SetValue(object obj, object value)
		{
			IPopulateHelperExtended iphe = (IPopulateHelperExtended)obj;
			// Fallback to the other solution, if not supported.
			if (!iphe.PropertyIsHandled(this.NAME))
			{
				_fallback.SetValue(obj, value);
				return;
			}

			if (IsUserDefinedType)
				((IUserDefinedType)iphe[NAME]).FromSimpleDataType(value);
			else
				iphe[NAME] = value;
		}
	}
}
